Skip to content

Update(zen-go): add claude-opus-4-8, minimax-m3, mimo-v2.5-free models and proper effort level integration for Zen/Go models - #1505

Merged
kevincodex1 merged 32 commits into
Twigpine:mainfrom
Gravirei:feat/opencode-zen-go-integration
Jun 10, 2026
Merged

kevincodex1 merged 32 commits into
Twigpine:mainfrom
Gravirei:feat/opencode-zen-go-integration

Conversation

@Gravirei

@Gravirei Gravirei commented Jun 3, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Expands the OpenCode Zen/Go integration with three new model registrations and adds xhigh as a first-class standard effort level, gated to only the models that actually accept it. The xhigh addition is what unlocks claude-opus-4-8 for the picker — without it the new model would only expose low/medium/high/max.

New models

Model Gateway Endpoint Notes
claude-opus-4-8 Zen /messages Reasoning + vision; supports max and xhigh effort.
minimax-m3 Go /messages Chat-only; defaults match the existing MiniMax Go family.
mimo-v2.5-free Zen /chat/completions Free tier; uses default OpenAI-compatible routing.

Model count, description strings, README, and docs/advanced-setup.md are bumped to match (Zen 41→43, Go 12→13).

Related: PR #1498 added opencode-minimax-m3-free to Zen. This PR is the Go counterpart of the M3 family plus two unrelated additions.

New effort level: xhigh (gated)

Promotes xhigh from an OpenAI-only value to a first-class EffortLevel and adds a modelSupportsXHighEffort allowlist (mirrors the existing modelSupportsMaxEffort pattern). xhigh surfaces only for:

  • OpenAI/Codex models on the openai / codex provider (existing behavior — they always had xhigh via OPENAI_EFFORT_LEVELS).
  • claude-opus-4-7 and claude-opus-4-8 (and the opencode- prefixed variants).

All other effort-supporting models — sonnet, haiku, claude-opus-4-6, 3P non-Claude models — do not see xhigh in the picker. A runtime clamp in resolveAppliedEffort also downgrades a stale persisted xhigh to high for non-supporting models, so a leftover settings.json value cannot surface as an API error.

Implementation:

  • EFFORT_LEVELS gains xhigh as a 5th level. EffortLevel type and Zod schemas (agent files, skill files, plugin agents/commands) now accept it.
  • getAvailableEffortLevels returns [low, medium, high, xhigh, max] for max- and xhigh-capable models, [low, medium, high, xhigh] for OpenAI/Codex, and [low, medium, high] for everything else. xhigh is ordered before max to match the natural progression.
  • toPersistableEffort and openAIEffortToStandard pass xhigh through unchanged. The previous normalization to max was a persistence shim that no longer applies once xhigh is a valid value in its own right.
  • claude-opus-4-8 is added to modelSupportsEffort, modelSupportsMaxEffort, and modelSupportsXHighEffort.

README updates

  • Added Atlas Cloud sponsor entry to the sponsors table.
  • Updated agent routing example to use zai-default and document the model override behavior (per-agent model can differ from catalog default), with explicit base_url and api_key keys in the example.

Test plan

  • bun test src/utils/effort.codex.test.ts src/integrations/gateways/opencode.test.ts src/integrations/index.test.ts src/integrations/compatibility.test.ts — all pass (75/75)
  • bun run build — clean
  • bun run integrations:generate — succeeds
  • modelSupportsXHighEffort returns true for opus-4-7, opus-4-8, and any model on the openai/codex provider; false for sonnet, haiku, and other Claude variants
  • getAvailableEffortLevels(claude-opus-4-8) = [low, medium, high, xhigh, max]
  • getAvailableEffortLevels(claude-sonnet-4-6) = [low, medium, high]
  • resolveAppliedEffort(claude-sonnet-4-6, xhigh) clamps to high
  • Manual: select claude-opus-4-8 in the model picker, pick xhigh in /effort, confirm the request reaches OpenCode and returns a successful response

Risk

xhigh is now scoped to a tight allowlist. There is no risk of a 1P or 3P user accidentally selecting xhigh on a model that will reject it — the picker hides the option, and the runtime clamp catches stale persisted values.

The Anthropic shim still maps xhigh → max at the request boundary, so wire format is unchanged for 1P models that do reach the API through other paths (no current path does, but the shim is left intact as a defense-in-depth).

Files changed

11 files, +216/-37 across the branch. Latest commit adds the modelSupportsXHighEffort gate and runtime clamp on top of the earlier xhigh work.

Summary by CodeRabbit

  • New Features

    • Added a new "xhigh" reasoning effort level and made it selectable/persistable for supported models.
    • Added three new models: Claude Opus 4.8, MiMo V2.5 Free, and MiniMax M3.
  • UI / CLI

    • Effort picker, model picker, and the CLI /effort help now show and accept xhigh; selections clamp to supported levels.
  • Documentation

    • Updated provider docs to reflect new model counts.

Gravirei and others added 19 commits May 24, 2026 23:37
Add OpenCode as a first-class provider, enabling users to connect their
Zen (pay-as-you-go) and Go ($10/mo) subscriptions via the /provider command.

New integration descriptors:
- vendors/opencode.ts — OpenCode Zen vendor (41 models)
- gateways/opencode-go.ts — OpenCode Go gateway (12 models)
- brands/opencode.ts — brand descriptor
- models/opencode.ts — full model catalog (GPT, Claude, Gemini, Qwen,
  GLM, Kimi, MiniMax, Grok, DeepSeek, MiMo, Nemotron)

Modified files:
- integrationArtifacts.generated.ts — register descriptors and presets
- providerProfile.ts — add OPENCODE_API_KEY env/secret key, 'opencode'
  profile type, and buildLaunchEnv handler
- providerConfig.ts — add DEFAULT_OPENCODE_BASE_URL constants

Auth: OPENCODE_API_KEY env var or interactive key entry in /provider
Transport: openai-compatible (chat_completions)
Base URLs: https://opencode.ai/zen/v1 (Zen), /zen/go/v1 (Go)
Add visual tags in the /provider preset selection to distinguish
OpenCode Zen (pay-as-you-go) from OpenCode Go (subscription).
Switch OpenCode vendor and Go gateway from static to hybrid model
catalog with openai-compatible discovery. Models are fetched from
/v1/models on startup and cached for 1 hour. Manual refresh is
supported via the /provider UI.

Static model list is preserved as fallback when discovery fails.
97 tests across 2 files covering:

Integration tests (72 tests):
- Vendor descriptor: id, label, classification, base URL, model, auth,
  transport, preset, validation, catalog, discovery, usage metadata
- Gateway descriptor: id, label, vendorId, category, base URL, model,
  auth, transport, preset, catalog, discovery
- Brand descriptor: id, label, canonicalVendorId, capabilities, modelIds
- Model catalog: registration, vendor/gateway associations, required
  fields, valid classifications, reasoning/coding tags, no duplicates,
  model counts (41 Zen, 12 Go), modelDescriptorId consistency
- Cross-reference: brand↔model, vendor↔model, gateway↔model,
  shared OPENCODE_API_KEY
- Registry validation: no errors, no preset conflicts
- Edge cases: unique ids, unique apiNames, non-empty labels, valid
  contextWindow/maxOutputTokens, valid defaultModel format, validation
  message content, discovery config

Profile tests (25 tests):
- Type guard: isProviderProfile('opencode'), rejects invalid values
- buildLaunchEnv: persisted env, defaults, process env precedence,
  OPENCODE_API_KEY mapping, whitespace/null/undefined/empty handling,
  very long keys, special characters, concurrent access, boundary
  values, no credential leakage
Add endpointPath field to OpenAIShimTransportConfig so catalog entries
can specify which API path to use per model. This addresses the
maintainer's [P1] finding that all models were routed to
/chat/completions regardless of their upstream endpoint.

Changes:
- descriptors.ts: add endpointPath?: string to OpenAIShimTransportConfig
- openaiShim.ts: buildRequestUrl checks shimConfig.endpointPath first
- vendors/opencode.ts: add transportOverrides to 31 catalog entries
  (GPT→/responses, Claude/Qwen→/messages, Gemini→/models/<id>)
  + switch to source: 'static' to prevent free models from live API
- gateways/opencode-go.ts: add transportOverrides to 4 entries
  (MiniMax/Qwen→/messages) + switch to source: 'static'
- opencode.test.ts: update tests for static source, remove discovery tests
…scriptors

- Add OpenCode Zen/Go rows to README supported providers table
- Add OpenCode Zen/Go examples and OPENCODE_API_KEY to advanced-setup.md
- Add PresetBadge type to descriptor/manifest with badge propagation in
  artifact generator
- Move 4 hard-coded preset badges ([FREE], [Sponsor], [Zen], [Go]) from
  ProviderManager.tsx into descriptor preset metadata
- Add badge field to providerUiMetadata so UI components read from manifest
- Update integration overview docs to recommend preset.badge for future
  gateways
…ssages and /responses (P1)

Extend the openaiShim transport so that endpointPath overrides select
both the URL and the correct body/response format:

- /responses → OpenAI Responses API body (input, max_output_tokens)
- /messages  → Anthropic Messages API body (content blocks, system, max_tokens)

Also fixes: abort listener leak in SSE passthrough, system prompt
content-block flattening, and removes [Zen]/[Go] badge entries (P3).

Co-Authored-By: OpenClaude (mimo-v2.5-pro) <openclaude@gitlawb.com>
…n Gemini models (P1)

The three Gemini models in the OpenCode Zen catalog (gemini-3.5-flash,
gemini-3.1-pro, gemini-3-flash) were sending chat-completions body to
the /models/gemini-* endpoint, which expects Google AI SDK format.

- effectiveTransport now detects /models/gemini- endpointPath → 'gemini'
- buildGeminiBody() converts Anthropic messages → Google contents[]
  with role mapping, systemInstruction, generationConfig, functionDeclarations
- geminiSseToAnthropic() parses Google SSE frames → Anthropic stream events
  with text deltas, functionCall tool_use, finishReason mapping
- _convertGeminiToAnthropicResponse() for non-streaming responses
- Streaming/non-streaming routing via URL detection (/models/gemini-)
- serializeBody(), hasToolsPayload, omitGeminiTools all updated
P1: Prefix all defaultModel values in opencode.ts with 'opencode-'
so the fallback findModelDescriptorForApiName() doesn't match
canonical model names. The OpenCode descriptors are still found
via catalog entry lookup when the OpenCode route is active.

P2: Add 'OpenCode Go' and 'OpenCode Zen' to PRESET_ORDER in
ProviderManager.test.tsx between 'OpenAI' and 'OpenRouter'
so navigateToPreset() sends the correct number of j keypresses.
- category: 'hosted' → 'aggregating' (both are aggregating gateways)
- add validation block with OPENCODE_API_KEY guidance
- update test assertion from 'hosted' to 'aggregating'
- fix(autocompact): retry circuit breaker after cooldown (Twigpine#1375)
- fix(provider): require API key input when adding OpenGateway (Twigpine#1384)
- fix(provider): allow remote Ollama without OPENAI_API_KEY (Twigpine#952)
- fix(codex-stream): recover tool args delivered only via done events (Twigpine#1262)
- fix: route MiniMax compacting through Anthropic-compatible API (Twigpine#1154)
- fix(thinking): disable thinking for unsupported Ollama models (Twigpine#1376)
- feat(agents): set active session agent from agents menu (Twigpine#1349)
- fix(repl): show permission prompts while draft input is present (Twigpine#1393)
- fix(model): include profile models in descriptor picker (Twigpine#1361)
- Improve warning notice formatting (Twigpine#1415)
- fix(codex): allow credential storage fallback (Twigpine#1347)
- fix(attribution): make git attribution opt-in by default (Twigpine#1335)
- fix(agent): allow custom model overrides (Twigpine#1337)
- feat(query): robust multi-lingual and structural continuation nudge (Twigpine#1280)
- fix(watchers): debounce skills and settings reload bursts (Twigpine#1370)
- feat: configure API retry backoff (Twigpine#370) (Twigpine#1095)
- chore(main): release 0.15.0 (Twigpine#1325)
- ci: retrigger CodeQL after action download outage (Twigpine#1374)
- Fix launcher heap setup for long sessions (Twigpine#1242)
When users set up OpenCode Zen/Go via /provider, the key is saved as
OPENAI_API_KEY (via buildCompatibilityProcessEnv). The validation block
only checked OPENCODE_API_KEY, causing a startup warning even though
the runtime auth header had the key it needed.

Add OPENAI_API_KEY to validation.credentialEnvVars for both gateways,
matching the pattern used by Hicap and Gitlawb Opengateway.
# Conflicts:
#	README.md
#	src/components/ProviderManager.tsx
#	src/integrations/gateways/gitlawb-opengateway.ts
#	src/integrations/generated/integrationArtifacts.generated.ts
#	src/utils/providerProfile.ts
- buildResponsesBody: add reasoning_effort + reasoning_summary + include
- buildAnthropicMessagesBody: add thinking config (adaptive/enabled/budget)
- buildGeminiBody: add thinkingConfig with thinkingLevel mapping
- modelSupportsEffort: allow OpenCode Claude and Gemini models
- modelSupportsMaxEffort: add opus-4-7
- getAvailableEffortLevels: show standard levels for OpenCode native models
- opencode-go: add missing validation block
@coderabbitai

coderabbitai Bot commented Jun 3, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 772235c0-583c-4c4b-9e1e-767a2b96ccf6

📥 Commits

Reviewing files that changed from the base of the PR and between 2fcb07d and 72fb746.

📒 Files selected for processing (1)
  • src/utils/effort.ts
📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx,py}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{ts,tsx,js,jsx,py}: Follow the existing code style in the touched files
Keep comments useful and concise

Files:

  • src/utils/effort.ts
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/utils/effort.ts
**

⚙️ CodeRabbit configuration file

**: # Contributing to OpenClaude

Thanks for contributing.

OpenClaude is a fast-moving open-source coding-agent CLI with support for multiple providers, local backends, MCP, and a terminal-first workflow. The best contributions here are focused, well-tested, and easy to review.

Before You Start

  • Search existing issues and discussions before opening a new thread.
  • Check open pull requests for work that overlaps with your contribution. If a PR already exists that addresses the same change, open an issue or discussion first to align on direction — duplicate PRs may be closed without review.
  • Use issues for confirmed bugs and actionable feature work.
  • Use discussions for setup help, ideas, and general community conversation.
  • For larger changes, open an issue first so the scope is clear before implementation.
  • For security reports, follow SECURITY.md.

Pull Requests

Every PR needs a reason. Your PR description must include:

  • what changed and why
  • the user or developer impact
  • the exact checks you ran
  • a linked issue when one exists, using Fixes fix: skip assertMinVersion for third-party providers #123, `Closes `#123, or another clear link
  • screenshots when the PR touches UI, terminal presentation, or the VS Code extension
  • which provider path was tested when the PR changes provider behavior

The PR author is responsible for ensuring their PR is merge-ready. PRs with merge conflicts will not be reviewed or approved until the conflicts are resolved.

Issues are the recommended starting point for anything non-trivial — opening one first helps avoid wasted effort if the change is out of scope or already being worked on. Small fixes, doc corrections, and obvious improvements can stand on their own without a linked issue, as long as the PR description explains the intent.

What Gets Closed Without Review

PRs may be closed without review...

Files:

  • src/utils/effort.ts
🔇 Additional comments (1)
src/utils/effort.ts (1)

96-98: LGTM!


📝 Walkthrough

Walkthrough

This PR introduces xhigh as a first-class effort level alongside low, medium, high, and max. Core logic detects model support, routes requests through provider-specific shim builders, and clamps unsupported values. Three OpenCode models are added; Zen and Go gateways are updated to reflect 43 and 13 total models respectively.

Changes

Effort Levels and Model Expansion

Layer / File(s) Summary
Effort type and constant foundation
src/entrypoints/sdk/runtimeTypes.ts, src/utils/effort.ts, src/entrypoints/sdk/coreSchemas.ts, src/entrypoints/sdk/controlSchemas.ts, src/utils/settings/types.ts, src/utils/model/modelSupportOverrides.ts, src/main.tsx
EffortLevel and schema/CLI enums expanded to include 'xhigh'; EFFORT_LEVELS and ModelCapabilityOverride updated; CLI --effort accepts xhigh.
Effort capability detection and mapping
src/utils/effort.ts
Model effort allowlists expanded for Opus/Sonnet/Gemini patterns; added modelSupportsXHighEffort; limited OpenAI-effort routing to openai/codex; getAvailableEffortLevels always returns EffortLevel[]; persistence/normalization updated and unsupported xhigh is clamped to high.
Effort feature tests
src/utils/effort.codex.test.ts
Tests added/updated to verify xhigh persistence, mapping, model support detection, available-level filtering, routing exclusions, and clamping behavior.
API shim: reasoning effort fields
src/services/api/openaiShim.ts
OpenAI Responses sets reasoning_effort and requests encrypted reasoning; Anthropic Messages converts xhigh → max and sets thinking/effort per model; Google Gemini adds thinkingConfig and maps xhigh → high.
SDK generated types refresh
src/entrypoints/sdk/coreTypes.generated.ts
Regenerated types: several permission-update fields become arrays; ModelInfo.supportedEffortLevels becomes optional array including xhigh; AgentDefinition.mcpServers becomes an array type.
Model catalog, gateway wiring, and counts
src/integrations/models/opencode.ts, src/integrations/gateways/opencode.ts, src/integrations/gateways/opencode-go.ts, src/integrations/gateways/opencode.test.ts, README.md, docs/advanced-setup.md
Added opencode-claude-opus-4-8, opencode-mimo-v2.5-free, and opencode-go-minimax-m3; wired gateway catalog entries with OpenAI-shim /messages overrides; updated gateway descriptions/tests/docs for 43/13 totals.
CLI and UI surface integration
src/cli/print.ts, src/main.tsx, src/commands/effort/effort.tsx, src/components/ModelPicker.tsx, src/components/EffortPicker.tsx
CLI model printer uses getAvailableEffortLevels; ModelPicker/EffortPicker use model-specific available levels for display, cycling, persistence, and clamping; effort command help text updated.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Gitlawb/openclaude#1497: Shapes ModelInfo.supportedEffortLevels as an array; this PR extends the array to include xhigh and updates core effort-handling logic.

Suggested reviewers

  • jatmn
  • kevincodex1
  • gnanam1990
🚥 Pre-merge checks | ✅ 5 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Risk Surface Disclosed ⚠️ Warning PR modifies provider routing (endpoint paths) and outbound behavior, but review only flagged feature issues (P2), not risk surface assessment. Review should explicitly assess whether new endpoint paths and effort parameter changes in openaiShim introduce security or routing risks.
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Title accurately summarizes the main changes: adding three new models and effort level integration for Zen/Go gateways.
Description check ✅ Passed Description fully covers changes with clear summary, impact, testing, and implementation details across all required sections.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No Hidden Policy Change ✅ Passed No hidden policy changes. PR is scoped to effort level enhancement and model additions. Permission, routing, telemetry systems untouched.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/advanced-setup.md`:
- Around line 197-199: Update the OpenCode Go model count in
docs/advanced-setup.md so the sentence that currently reads “12 open models”
matches the rest of the PR (change to “13 open models”); locate the OpenCode Go
description near the OpenCode Zen paragraph and replace the numeric count text
for OpenCode Go to 13 to keep the section consistent.

In `@src/services/api/openaiShim.ts`:
- Around line 2291-2307: The adaptive-model detection misses opus 4.8, so update
the isAdaptive check (the variable computed from modelLower near
modelLower.includes(...) and the related isOpus45 branch) to include the 4.8
variants (e.g., 'opus-4-8' and 'opus-4.8' and, if applicable,
'sonnet-4-8'/'sonnet-4.8') so that for claude-opus-4-8 the path that sets
anthropicBody.thinking = { type: 'adaptive' } and anthropicBody.effort = effort
is used instead of falling back to the budgetTokens branch; keep the existing
isOpus45 logic unchanged.

In `@src/utils/effort.ts`:
- Around line 97-99: The current early return in modelUsesOpenAIEffort only
checks provider and thus treats native OpenCode/gemini routes as OpenAI-style,
enabling xhigh incorrectly; update modelUsesOpenAIEffort to require both
provider === 'openai' AND an explicit marker that the model implements
OpenAI/chat-style semantics (for example a capability flag like supportsChat or
apiStyle === 'openai' / family startsWith('gpt-')), explicitly excluding native
OpenCode routes (e.g., models flagged as open_code or route type 'messages' that
are not OpenAI-compatible); ensure getAvailableEffortLevels and
modelSupportsXHighEffort call the revised modelUsesOpenAIEffort so
resolveAppliedEffort’s clamping behaves correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d374ad16-bfea-46fa-b734-9687d5cff4cb

📥 Commits

Reviewing files that changed from the base of the PR and between 3659eaa and 4bb3552.

⛔ Files ignored due to path filters (1)
  • src/integrations/generated/integrationArtifacts.generated.ts is excluded by !**/generated/**
📒 Files selected for processing (10)
  • README.md
  • docs/advanced-setup.md
  • src/entrypoints/sdk/runtimeTypes.ts
  • src/integrations/gateways/opencode-go.ts
  • src/integrations/gateways/opencode.test.ts
  • src/integrations/gateways/opencode.ts
  • src/integrations/models/opencode.ts
  • src/services/api/openaiShim.ts
  • src/utils/effort.codex.test.ts
  • src/utils/effort.ts

Comment thread docs/advanced-setup.md
Comment thread src/services/api/openaiShim.ts
Comment thread src/utils/effort.ts
- docs/advanced-setup.md: bump OpenCode Go count 12 → 13
- openaiShim.ts: include opus-4-8 / opus-4.8 in the adaptive thinking
  detection so the new model uses the adaptive + effort path instead
  of falling back to budgetTokens
- effort.ts: modelUsesOpenAIEffort now also rejects models that include
  'claude-' or 'gemini-' — without this, OpenCode Claude/Gemini
  routes (provider=openai) were misclassified as OpenAI-style and
  could leak xhigh past the new gate
- effort.codex.test.ts: lock in the new exclusion with a regression
  test against the openai provider

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Gravirei Gravirei changed the title Update(zen-go): add claude-opus-4-8, minimax-m3, mimo-v2.5-free models and xhigh effort level Update(zen-go): add claude-opus-4-8, minimax-m3, mimo-v2.5-free models and proper effort level integration for Zen/Go models Jun 3, 2026

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found a few issues that need to be addressed before this is ready.

Findings

  • [P2] Accept xhigh in the persisted settings schema before writing it
    src/utils/effort.ts:202
    toPersistableEffort() now returns xhigh, and the /effort, effort callout, and model picker paths all write that value back to userSettings.effortLevel. The settings schema still only accepts low | medium | high | max, so the changed callers now hit TypeScript errors and a persisted xhigh setting will be rejected/parsed away instead of surviving restart. Please update the settings contract anywhere effortLevel is validated or inferred before making xhigh persistable.

  • [P2] Include xhigh in the model picker effort cycle for supported models
    src/components/ModelPicker.tsx:445
    The /model picker still decides the available cycle from a boolean includeMax, so even on claude-opus-4-8 the arrow controls only cycle through low, medium, high, and max. This leaves the new model unable to select the xhigh level from the model switch flow even though the PR adds it specifically for that model. Please drive this picker from the same available-level helper used by /effort, or add an explicit xhigh-capable branch.

  • [P2] Keep SDK/control effort metadata in sync with the new level
    src/cli/print.ts:1213
    The SDK/control model info still builds supportedEffortLevels from modelSupportsMaxEffort() ? [...EFFORT_LEVELS] : ..., and EFFORT_LEVELS now includes xhigh. That over-advertises xhigh for max-capable models that do not support it, such as opus-4-6, while the generated ModelInfoSchema/types still reject xhigh entirely. The PR typecheck now fails at the initialize response with supportedEffortLevels containing xhigh. Please use the model-specific available-level logic here and regenerate/update the SDK schema/types so control clients see the same contract as the CLI.

@Gravirei

Gravirei commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

I found a few issues that need to be addressed before this is ready.

Findings

* [P2] Accept `xhigh` in the persisted settings schema before writing it
  `src/utils/effort.ts:202`
  `toPersistableEffort()` now returns `xhigh`, and the `/effort`, effort callout, and model picker paths all write that value back to `userSettings.effortLevel`. The settings schema still only accepts `low | medium | high | max`, so the changed callers now hit TypeScript errors and a persisted `xhigh` setting will be rejected/parsed away instead of surviving restart. Please update the settings contract anywhere `effortLevel` is validated or inferred before making `xhigh` persistable.

* [P2] Include `xhigh` in the model picker effort cycle for supported models
  `src/components/ModelPicker.tsx:445`
  The `/model` picker still decides the available cycle from a boolean `includeMax`, so even on `claude-opus-4-8` the arrow controls only cycle through `low`, `medium`, `high`, and `max`. This leaves the new model unable to select the `xhigh` level from the model switch flow even though the PR adds it specifically for that model. Please drive this picker from the same available-level helper used by `/effort`, or add an explicit xhigh-capable branch.

* [P2] Keep SDK/control effort metadata in sync with the new level
  `src/cli/print.ts:1213`
  The SDK/control model info still builds `supportedEffortLevels` from `modelSupportsMaxEffort() ? [...EFFORT_LEVELS] : ...`, and `EFFORT_LEVELS` now includes `xhigh`. That over-advertises `xhigh` for max-capable models that do not support it, such as `opus-4-6`, while the generated `ModelInfoSchema`/types still reject `xhigh` entirely. The PR typecheck now fails at the initialize response with `supportedEffortLevels` containing `xhigh`. Please use the model-specific available-level logic here and regenerate/update the SDK schema/types so control clients see the same contract as the CLI.

Working on it....

Gravirei and others added 3 commits June 3, 2026 23:16
Closes the three P2 findings from PR Twigpine#1505 review:

1. Settings schema now accepts 'xhigh' so a persisted xhigh survives
   restart instead of being silently dropped by .catch(undefined).
2. ModelPicker /effort cycle is driven by getAvailableEffortLevels(model)
   instead of a boolean includeMax, so models supporting xhigh
   (opus-4-7/4-8, OpenAI/Codex) can actually select it from the picker.
   displayEffort clamp now uses the available levels list, so stale
   xhigh also clamps to high when the focused model doesn't support it.
3. SDK/control metadata uses getAvailableEffortLevels(model) instead of
   the EFFORT_LEVELS fallback that advertised xhigh to every max-capable
   model. SDK schema + generated types extended to include 'xhigh'.

Also fixes a latent generator bug: the array case in generate-sdk-types
now parenthesizes union/intersection elements so the trailing [] binds
the whole type, e.g. ("a"|"b")[] rather than "a"|"b[]. Without this,
the regenerated xhigh levels ended up typed as the single-literal
"xhigh"[] and broke the modelInfo assignability check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
EFFORT_LEVELS now matches getAvailableEffortLevels() output order
(['low', 'medium', 'high', 'xhigh', 'max']), and the order asserted by
the existing effort.codex.test.ts tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Matches the EFFORT_LEVELS / getAvailableEffortLevels order from the
previous commit. The Zod enum order doesn't affect runtime validation,
but keeps the source consistent and avoids confusion if anyone reads
the enum literal to infer display order.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Gravirei

Gravirei commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

Pushed 3 new commits on top of the previous PR tip to address the three [P2] findings from the review:

78a955e — address reviewer feedback on xhigh effort + new models

  1. Settings schema (src/utils/settings/types.ts) — effortLevel Zod enum now includes 'xhigh', so a persisted xhigh survives restart instead of being silently dropped by .catch(undefined).
  2. ModelPicker (src/components/ModelPicker.tsx) — /effort cycle is driven by getAvailableEffortLevels(model) instead of a boolean includeMax, so xhigh-capable models (opus-4-7/4-8, OpenAI/Codex) can actually select it. The displayEffort clamp also uses the available levels list, so a stale xhigh from another model clamps to high.
  3. SDK/control metadata (src/cli/print.ts, coreSchemas.ts, regenerated coreTypes.generated.ts) — replaced the EFFORT_LEVELS fallback (which over-advertised xhigh to every max-capable model) with getAvailableEffortLevels(resolvedModel). The SDK schema and generated types now include 'xhigh'.

Side-fix: the array case in scripts/generate-sdk-types.ts now parenthesizes union/intersection elements so [] binds the whole type (e.g. ("a"|"b")[] not "a"|"b[]). Without this, the regenerated xhigh levels typed as the single-literal "xhigh"[] and broke the modelInfo assignability check. The diff against the typecheck baseline shows 12 fewer type errors on the branch.

Also normalized the EFFORT_LEVELS and Zod enum order to ['low', 'medium', 'high', 'xhigh', 'max'] so source order matches getAvailableEffortLevels() output and the test assertions (6e2fce5, bf45bea). The Zod enum order doesn't affect runtime validation — purely a source-consistency clean-up.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/components/ModelPicker.tsx (2)

184-197: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clamp the selected effort, not just the rendered label.

Lines 184-197 only normalize what the picker displays. If a user picks xhigh, moves focus to a model whose focusedAvailableLevels no longer include it, and presses Enter, handleSelect still persists and emits the raw effort from Lines 254-267. Runtime clamping hides the API error later, but the picker itself reports a value the focused model does not support.

Also applies to: 248-267

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ModelPicker.tsx` around lines 184 - 197, The picker currently
only clamps the rendered label (displayEffort) when the focused model doesn't
support the current effort, but leaves the actual selected value unchanged;
update the logic so the selected/committed effort is clamped as well: when
computing focusedAvailableLevels (via resolveOptionModel and
getAvailableEffortLevels) and focusedDefaultEffort (via
getDefaultEffortLevelForOption), ensure the variable used by handleSelect is
replaced or normalized to a supported value (use focusedDefaultEffort or the
nearest available level) instead of the raw effort; adjust the code paths around
displayEffort and the selection handler (handleSelect) so both display and
persisted/emailed effort values are determined from the clamped value rather
than the original effort variable.

170-187: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Re-key effort cycling to include focusedAvailableLevels (and align selection/persistence with supported levels).

  • handleCycleEffort is only regenerated when focusedDefaultEffort, focusedSupportsEffort, and focusedSupportsMax change, but it closes over focusedAvailableLevels; when switching between models where only xhigh availability differs, cycling can use a stale level set (making xhigh unreachable or causing incorrect cycling).
  • UI clamps the displayed effort to "high" when unsupported, but handleSelect/persistence emits the raw effort (including xhigh) without verifying it’s in the focused model’s getAvailableEffortLevels, creating a display-vs-selection mismatch.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ModelPicker.tsx` around lines 170 - 187, The handler
generation and selection logic close over a stale set of available effort
levels: update the code so handleCycleEffort is re-created when
focusedAvailableLevels changes (add focusedAvailableLevels to its dependency
list alongside focusedDefaultEffort, focusedSupportsEffort and
focusedSupportsMax) and adjust handleSelect to validate/clamp the chosen effort
against getAvailableEffortLevels(resolveOptionModel(focusedValue)) before
emitting/persisting it (so displayed/clamped values like "high" and persisted
values are always from focusedAvailableLevels); also ensure any places using
focusedSupportsEffort/focusedSupportsMax still derive those from
resolveOptionModel(focusedValue) consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/components/ModelPicker.tsx`:
- Around line 184-197: The picker currently only clamps the rendered label
(displayEffort) when the focused model doesn't support the current effort, but
leaves the actual selected value unchanged; update the logic so the
selected/committed effort is clamped as well: when computing
focusedAvailableLevels (via resolveOptionModel and getAvailableEffortLevels) and
focusedDefaultEffort (via getDefaultEffortLevelForOption), ensure the variable
used by handleSelect is replaced or normalized to a supported value (use
focusedDefaultEffort or the nearest available level) instead of the raw effort;
adjust the code paths around displayEffort and the selection handler
(handleSelect) so both display and persisted/emailed effort values are
determined from the clamped value rather than the original effort variable.
- Around line 170-187: The handler generation and selection logic close over a
stale set of available effort levels: update the code so handleCycleEffort is
re-created when focusedAvailableLevels changes (add focusedAvailableLevels to
its dependency list alongside focusedDefaultEffort, focusedSupportsEffort and
focusedSupportsMax) and adjust handleSelect to validate/clamp the chosen effort
against getAvailableEffortLevels(resolveOptionModel(focusedValue)) before
emitting/persisting it (so displayed/clamped values like "high" and persisted
values are always from focusedAvailableLevels); also ensure any places using
focusedSupportsEffort/focusedSupportsMax still derive those from
resolveOptionModel(focusedValue) consistently.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d324d1cc-2fd3-42ed-a424-d54ce21ca358

📥 Commits

Reviewing files that changed from the base of the PR and between ecfa287 and bf45bea.

📒 Files selected for processing (7)
  • scripts/generate-sdk-types.ts
  • src/cli/print.ts
  • src/components/ModelPicker.tsx
  • src/entrypoints/sdk/coreSchemas.ts
  • src/entrypoints/sdk/coreTypes.generated.ts
  • src/utils/effort.ts
  • src/utils/settings/types.ts
✅ Files skipped from review due to trivial changes (1)
  • src/entrypoints/sdk/coreTypes.generated.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/utils/effort.ts

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 5, 2026
@Gravirei

Gravirei commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

Addressed both reviewer findings from @jatmn (CodeRabbit) in commit 7d65569:

P2 — narrow the effort allowlist: Collapsed the two 4-model branches in src/utils/effort.ts:45 into one that matches the Anthropic /messages shim's isAdaptive || isOpus45 set (opus-4-5/4-6/4-7/4-8, sonnet-4-6). Older variants like claude-opus-4-1 and claude-sonnet-4-5 no longer advertise effort — the substring match that previously included them was the source of the silent low/medium drop on the wire. The substring check still catches prefix variations (claude-, opencode-claude-).

P3 — sync max description: Updated getEffortLevelDescription('max') from "Opus 4.6 only" to "Opus 4.6+" to match modelSupportsMaxEffort's new 4.6/4.7/4.8 allowlist and the /effort --help text from 3cf5de2.

New test in src/utils/effort.codex.test.ts covers both directions of the narrowing: opus-4-5/4-6/4-7/4-8 and sonnet-4-6 → effort supported; opus-4-1, opus-4-2, sonnet-4-5 → [].

All 12 effort codex tests pass.

@Gravirei
Gravirei requested a review from jatmn June 5, 2026 05:05
jatmn
jatmn previously approved these changes Jun 5, 2026

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update. I rechecked the previously discussed paths and do not see any remaining actionable issues from my side.

@jatmn

jatmn commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

@kevincodex1

…o-integration

# Conflicts:
#	scripts/generate-sdk-types.ts
#	src/entrypoints/sdk/coreTypes.generated.ts
@Gravirei
Gravirei dismissed stale reviews from jatmn and coderabbitai[bot] via 2fcb07d June 8, 2026 15:39

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 42-46: The PR description and AI summary do not mention the Atlas
Cloud sponsor entry that was added alongside the model catalog update; update
the PR description to explicitly list the sponsor addition (the "Atlas Cloud"
banner/sponsor entry in README) as one of the PR objectives and include a short
note in the AI summary so the commit history and reviewers can see this doc-only
change.
- Around line 213-217: The PR description is missing mention of the agent
routing example change: update the PR objectives/AI summary to note that the
agent routing example now uses the "zai-default" entry and that the example
documents the "model" override behavior (i.e., that per-agent "model" can differ
from the catalog default); explicitly reference the keys shown ("zai-default",
"model", "base_url", "api_key") and add a short sentence in the PR description
summarizing these changes and that this update is bundled with the model catalog
update (also ensure similar note is added where the README lines around the
other occurrences are referenced).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 38abfe89-2b4c-47f3-91bb-c73fac02de57

📥 Commits

Reviewing files that changed from the base of the PR and between 7d65569 and 2fcb07d.

⛔ Files ignored due to path filters (1)
  • src/entrypoints/sdk/coreTypes.generated.ts is excluded by !src/entrypoints/sdk/coreTypes.generated.ts
📒 Files selected for processing (5)
  • README.md
  • src/entrypoints/sdk/coreSchemas.ts
  • src/main.tsx
  • src/services/api/openaiShim.ts
  • src/utils/settings/types.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (6)
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • README.md
  • src/main.tsx
  • src/utils/settings/types.ts
  • src/entrypoints/sdk/coreSchemas.ts
  • src/services/api/openaiShim.ts
{README.md,CONTRIBUTING.md,docs/**,.github/pull_request_template.md}

⚙️ CodeRabbit configuration file

{README.md,CONTRIBUTING.md,docs/**,.github/pull_request_template.md}: Review docs for accuracy against current code behavior. Flag security or provider claims that overpromise, stale install commands, missing setup caveats, and instructions that could push users toward unsafe credential handling. Keep purely wording-level suggestions non-blocking.

Files:

  • README.md
**

⚙️ CodeRabbit configuration file

**: # Contributing to OpenClaude

Thanks for contributing.

OpenClaude is a fast-moving open-source coding-agent CLI with support for multiple providers, local backends, MCP, and a terminal-first workflow. The best contributions here are focused, well-tested, and easy to review.

Before You Start

  • Search existing issues and discussions before opening a new thread.
  • Check open pull requests for work that overlaps with your contribution. If a PR already exists that addresses the same change, open an issue or discussion first to align on direction — duplicate PRs may be closed without review.
  • Use issues for confirmed bugs and actionable feature work.
  • Use discussions for setup help, ideas, and general community conversation.
  • For larger changes, open an issue first so the scope is clear before implementation.
  • For security reports, follow SECURITY.md.

Pull Requests

Every PR needs a reason. Your PR description must include:

  • what changed and why
  • the user or developer impact
  • the exact checks you ran
  • a linked issue when one exists, using Fixes #123, `Closes `#123, or another clear link
  • screenshots when the PR touches UI, terminal presentation, or the VS Code extension
  • which provider path was tested when the PR changes provider behavior

The PR author is responsible for ensuring their PR is merge-ready. PRs with merge conflicts will not be reviewed or approved until the conflicts are resolved.

Issues are the recommended starting point for anything non-trivial — opening one first helps avoid wasted effort if the change is out of scope or already being worked on. Small fixes, doc corrections, and obvious improvements can stand on their own without a linked issue, as long as the PR description explains the intent.

What Gets Closed Without Review

PRs may be closed without review...

Files:

  • README.md
  • src/main.tsx
  • src/utils/settings/types.ts
  • src/entrypoints/sdk/coreSchemas.ts
  • src/services/api/openaiShim.ts
{bin/**,scripts/**,package.json,src/setup.ts,src/main.tsx,src/entrypoints/**}

⚙️ CodeRabbit configuration file

{bin/**,scripts/**,package.json,src/setup.ts,src/main.tsx,src/entrypoints/**}: Review install, launcher, build, packaging, startup, and entrypoint changes for cross-platform compatibility, tracked-source rewrites, env/config precedence, and release safety. Block on changes that can break Windows/macOS/Linux startup or publish unexpected artifacts.

Files:

  • src/main.tsx
  • src/entrypoints/sdk/coreSchemas.ts
src/{components/permissions,utils/permissions,hooks/toolPermission,tools,entrypoints/sdk}/**

⚙️ CodeRabbit configuration file

src/{components/permissions,utils/permissions,hooks/toolPermission,tools,entrypoints/sdk}/**: Review permission prompts, auto-allow logic, sandbox behavior, SDK permission schemas, shell/PowerShell execution, and background execution paths as security-sensitive. Block on bypasses, unclear trust boundaries, unsafe path handling, missing user visibility, or changes that broaden allowed behavior without an explicit maintainer decision.

Files:

  • src/entrypoints/sdk/coreSchemas.ts
{src/services/api/**,src/integrations/**,src/utils/model/**,src/utils/provider*.ts,src/commands/provider/**}

⚙️ CodeRabbit configuration file

{src/services/api/**,src/integrations/**,src/utils/model/**,src/utils/provider*.ts,src/commands/provider/**}: Review provider routing, model selection, env precedence, auth/token handling, OpenAI-compatible shims, retries, proxy behavior, and outbound HTTP behavior with high scrutiny. Block on silent default changes, hidden fallback expansion, credential reuse mistakes, hardcoded provider assumptions, or new network reach that is not intentional and documented.

Files:

  • src/services/api/openaiShim.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: Gitlawb/openclaude PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-06-04T22:10:40.834Z
Learning: Verify that product, trust-model, routing-default, telemetry/network, and permission-policy changes are not hidden inside unrelated cleanup. Flag the PR if the policy decision needs explicit maintainer alignment.
🔇 Additional comments (5)
src/entrypoints/sdk/coreSchemas.ts (1)

65-79: LGTM!

Also applies to: 1114-1115

src/utils/settings/types.ts (1)

740-742: LGTM!

Also applies to: 753-766

src/services/api/openaiShim.ts (1)

1927-1927: LGTM!

Also applies to: 2200-2200, 2215-2215, 2293-2297, 2465-2467, 2549-2549, 2576-2578, 2640-2643, 2877-2879

src/main.tsx (1)

226-228: LGTM!

Also applies to: 271-272, 351-357, 373-374, 381-382, 735-737, 954-961, 3050-3050

README.md (1)

171-172: LGTM!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 42-46: The PR description and AI summary do not mention the Atlas
Cloud sponsor entry that was added alongside the model catalog update; update
the PR description to explicitly list the sponsor addition (the "Atlas Cloud"
banner/sponsor entry in README) as one of the PR objectives and include a short
note in the AI summary so the commit history and reviewers can see this doc-only
change.
- Around line 213-217: The PR description is missing mention of the agent
routing example change: update the PR objectives/AI summary to note that the
agent routing example now uses the "zai-default" entry and that the example
documents the "model" override behavior (i.e., that per-agent "model" can differ
from the catalog default); explicitly reference the keys shown ("zai-default",
"model", "base_url", "api_key") and add a short sentence in the PR description
summarizing these changes and that this update is bundled with the model catalog
update (also ensure similar note is added where the README lines around the
other occurrences are referenced).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 38abfe89-2b4c-47f3-91bb-c73fac02de57

📥 Commits

Reviewing files that changed from the base of the PR and between 7d65569 and 2fcb07d.

⛔ Files ignored due to path filters (1)
  • src/entrypoints/sdk/coreTypes.generated.ts is excluded by !src/entrypoints/sdk/coreTypes.generated.ts
📒 Files selected for processing (5)
  • README.md
  • src/entrypoints/sdk/coreSchemas.ts
  • src/main.tsx
  • src/services/api/openaiShim.ts
  • src/utils/settings/types.ts
📜 Review details
🔇 Additional comments (5)
src/entrypoints/sdk/coreSchemas.ts (1)

65-79: LGTM!

Also applies to: 1114-1115

src/utils/settings/types.ts (1)

740-742: LGTM!

Also applies to: 753-766

src/services/api/openaiShim.ts (1)

1927-1927: LGTM!

Also applies to: 2200-2200, 2215-2215, 2293-2297, 2465-2467, 2549-2549, 2576-2578, 2640-2643, 2877-2879

src/main.tsx (1)

226-228: LGTM!

Also applies to: 271-272, 351-357, 373-374, 381-382, 735-737, 954-961, 3050-3050

README.md (1)

171-172: LGTM!

🛑 Comments failed to post (2)
README.md (2)

42-46: 🧹 Nitpick | 🔵 Trivial

Document the sponsor addition in the PR description.

The Atlas Cloud sponsor entry is bundled with the model catalog update but not mentioned in the PR objectives or AI summary. For commit history clarity, the PR description should list all changes, even when they are doc-only.

Also applies to: 53-53

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 42 - 46, The PR description and AI summary do not
mention the Atlas Cloud sponsor entry that was added alongside the model catalog
update; update the PR description to explicitly list the sponsor addition (the
"Atlas Cloud" banner/sponsor entry in README) as one of the PR objectives and
include a short note in the AI summary so the commit history and reviewers can
see this doc-only change.

213-217: 🧹 Nitpick | 🔵 Trivial

Document the agent routing example update in the PR description.

The agent routing example was updated to use zai-default and includes additional explanation of the model override behavior. This change is bundled with the model catalog update but not mentioned in the PR objectives or AI summary.

Also applies to: 227-227, 235-235

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 213 - 217, The PR description is missing mention of
the agent routing example change: update the PR objectives/AI summary to note
that the agent routing example now uses the "zai-default" entry and that the
example documents the "model" override behavior (i.e., that per-agent "model"
can differ from the catalog default); explicitly reference the keys shown
("zai-default", "model", "base_url", "api_key") and add a short sentence in the
PR description summarizing these changes and that this update is bundled with
the model catalog update (also ensure similar note is added where the README
lines around the other occurrences are referenced).

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update. I rechecked the previously discussed effort-routing paths and found one issue that still needs to be addressed.

Findings

  • [P2] Complete the xhigh gate for non-effort OpenCode models
    src/utils/effort.ts:100
    CodeRabbit's earlier request to keep xhigh scoped to models that actually support it is marked addressed, but the current guard still returns true for every model that modelUsesOpenAIEffort() classifies as OpenAI-shaped. That leaves models such as opencode-go-minimax-m3 and mimo-v2.5-free with modelSupportsEffort() === false and no picker effort levels, while resolveAppliedEffort(model, 'xhigh') still returns xhigh instead of clamping. From there getAnthropicClient() turns the value into request.reasoning.effort, and the /messages shim maps xhigh to max/thinking controls for non-adaptive models, so a stale settings.json value or explicit --effort xhigh can still send unsupported effort fields to the newly added OpenCode Go MiniMax path and other non-effort OpenAI-compatible models. Please complete that gating fix by requiring actual effort/xhigh support for this branch, or by making resolveAppliedEffort() clamp any xhigh value when the target model does not support effort.

@Gravirei

Gravirei commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

Addressed: xhigh gate now requires modelSupportsEffort

modelSupportsXHighEffort was returning true for any OpenAI-shaped model (OpenCode Go/Zen models on the openai provider that arent Claude/Gemini), even when the model doesnt support effort at all. This meant models like opencode-go-minimax-m3 and mimo-v2.5-free would report xhigh as supported, and resolveAppliedEffort would not clamp stale xhigh values.

Fix: added !modelSupportsEffort(model) → false guard at the top of modelSupportsXHighEffort. Non-effort models now correctly return false, so resolveAppliedEfforts existing clamp (xhigh && !modelSupportsXHighEffort → high) catches any stale persisted or explicitly set xhigh values for those models.

@Gravirei
Gravirei requested a review from jatmn June 8, 2026 23:45

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update. I rechecked the previously discussed paths and do not see any remaining actionable issues from my side.

@kevincodex1 LGT

@kevincodex1 kevincodex1 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! thank you for this

@kevincodex1
kevincodex1 merged commit 286d403 into Twigpine:main Jun 10, 2026
3 checks passed
@Gravirei
Gravirei deleted the feat/opencode-zen-go-integration branch June 10, 2026 06:52
deagwon97 pushed a commit to deagwon97/openclaude that referenced this pull request Jun 11, 2026
…s and proper effort level integration for Zen/Go models (Twigpine#1505)

* feat(provider): add OpenCode Zen/Go subscription support

Add OpenCode as a first-class provider, enabling users to connect their
Zen (pay-as-you-go) and Go ($10/mo) subscriptions via the /provider command.

New integration descriptors:
- vendors/opencode.ts — OpenCode Zen vendor (41 models)
- gateways/opencode-go.ts — OpenCode Go gateway (12 models)
- brands/opencode.ts — brand descriptor
- models/opencode.ts — full model catalog (GPT, Claude, Gemini, Qwen,
  GLM, Kimi, MiniMax, Grok, DeepSeek, MiMo, Nemotron)

Modified files:
- integrationArtifacts.generated.ts — register descriptors and presets
- providerProfile.ts — add OPENCODE_API_KEY env/secret key, 'opencode'
  profile type, and buildLaunchEnv handler
- providerConfig.ts — add DEFAULT_OPENCODE_BASE_URL constants

Auth: OPENCODE_API_KEY env var or interactive key entry in /provider
Transport: openai-compatible (chat_completions)
Base URLs: https://opencode.ai/zen/v1 (Zen), /zen/go/v1 (Go)

* feat(provider): add [Zen]/[Go] tags to OpenCode preset labels

Add visual tags in the /provider preset selection to distinguish
OpenCode Zen (pay-as-you-go) from OpenCode Go (subscription).

* feat(provider): enable dynamic model discovery for OpenCode

Switch OpenCode vendor and Go gateway from static to hybrid model
catalog with openai-compatible discovery. Models are fetched from
/v1/models on startup and cached for 1 hour. Manual refresh is
supported via the /provider UI.

Static model list is preserved as fallback when discovery fails.

* test(provider): add comprehensive OpenCode Zen/Go test suite

97 tests across 2 files covering:

Integration tests (72 tests):
- Vendor descriptor: id, label, classification, base URL, model, auth,
  transport, preset, validation, catalog, discovery, usage metadata
- Gateway descriptor: id, label, vendorId, category, base URL, model,
  auth, transport, preset, catalog, discovery
- Brand descriptor: id, label, canonicalVendorId, capabilities, modelIds
- Model catalog: registration, vendor/gateway associations, required
  fields, valid classifications, reasoning/coding tags, no duplicates,
  model counts (41 Zen, 12 Go), modelDescriptorId consistency
- Cross-reference: brand↔model, vendor↔model, gateway↔model,
  shared OPENCODE_API_KEY
- Registry validation: no errors, no preset conflicts
- Edge cases: unique ids, unique apiNames, non-empty labels, valid
  contextWindow/maxOutputTokens, valid defaultModel format, validation
  message content, discovery config

Profile tests (25 tests):
- Type guard: isProviderProfile('opencode'), rejects invalid values
- buildLaunchEnv: persisted env, defaults, process env precedence,
  OPENCODE_API_KEY mapping, whitespace/null/undefined/empty handling,
  very long keys, special characters, concurrent access, boundary
  values, no credential leakage

* fix(provider): add per-model endpoint routing (P1)

Add endpointPath field to OpenAIShimTransportConfig so catalog entries
can specify which API path to use per model. This addresses the
maintainer's [P1] finding that all models were routed to
/chat/completions regardless of their upstream endpoint.

Changes:
- descriptors.ts: add endpointPath?: string to OpenAIShimTransportConfig
- openaiShim.ts: buildRequestUrl checks shimConfig.endpointPath first
- vendors/opencode.ts: add transportOverrides to 31 catalog entries
  (GPT→/responses, Claude/Qwen→/messages, Gemini→/models/<id>)
  + switch to source: 'static' to prevent free models from live API
- gateways/opencode-go.ts: add transportOverrides to 4 entries
  (MiniMax/Qwen→/messages) + switch to source: 'static'
- opencode.test.ts: update tests for static source, remove discovery tests

* refactor(opencode): model OpenCode Zen/Go as gateways (P2)

* docs(provider): document OpenCode setup and move badge metadata to descriptors

- Add OpenCode Zen/Go rows to README supported providers table
- Add OpenCode Zen/Go examples and OPENCODE_API_KEY to advanced-setup.md
- Add PresetBadge type to descriptor/manifest with badge propagation in
  artifact generator
- Move 4 hard-coded preset badges ([FREE], [Sponsor], [Zen], [Go]) from
  ProviderManager.tsx into descriptor preset metadata
- Add badge field to providerUiMetadata so UI components read from manifest
- Update integration overview docs to recommend preset.badge for future
  gateways

* fix(provider): match request body to endpoint format for OpenCode /messages and /responses (P1)

Extend the openaiShim transport so that endpointPath overrides select
both the URL and the correct body/response format:

- /responses → OpenAI Responses API body (input, max_output_tokens)
- /messages  → Anthropic Messages API body (content blocks, system, max_tokens)

Also fixes: abort listener leak in SSE passthrough, system prompt
content-block flattening, and removes [Zen]/[Go] badge entries (P3).

Co-Authored-By: OpenClaude (mimo-v2.5-pro) <openclaude@gitlawb.com>

* fix(provider): add Google AI SDK body/response format for OpenCode Zen Gemini models (P1)

The three Gemini models in the OpenCode Zen catalog (gemini-3.5-flash,
gemini-3.1-pro, gemini-3-flash) were sending chat-completions body to
the /models/gemini-* endpoint, which expects Google AI SDK format.

- effectiveTransport now detects /models/gemini- endpointPath → 'gemini'
- buildGeminiBody() converts Anthropic messages → Google contents[]
  with role mapping, systemInstruction, generationConfig, functionDeclarations
- geminiSseToAnthropic() parses Google SSE frames → Anthropic stream events
  with text deltas, functionCall tool_use, finishReason mapping
- _convertGeminiToAnthropicResponse() for non-streaming responses
- Streaming/non-streaming routing via URL detection (/models/gemini-)
- serializeBody(), hasToolsPayload, omitGeminiTools all updated

* fix: prevent OpenCode model descriptors from shadowing canonical limits

P1: Prefix all defaultModel values in opencode.ts with 'opencode-'
so the fallback findModelDescriptorForApiName() doesn't match
canonical model names. The OpenCode descriptors are still found
via catalog entry lookup when the OpenCode route is active.

P2: Add 'OpenCode Go' and 'OpenCode Zen' to PRESET_ORDER in
ProviderManager.test.tsx between 'OpenAI' and 'OpenRouter'
so navigateToPreset() sends the correct number of j keypresses.

* fix: align OpenCode Go descriptor metadata with Zen

- category: 'hosted' → 'aggregating' (both are aggregating gateways)
- add validation block with OPENCODE_API_KEY guidance
- update test assertion from 'hosted' to 'aggregating'

* fix: accept OPENAI_API_KEY as fallback in OpenCode validation

When users set up OpenCode Zen/Go via /provider, the key is saved as
OPENAI_API_KEY (via buildCompatibilityProcessEnv). The validation block
only checked OPENCODE_API_KEY, causing a startup warning even though
the runtime auth header had the key it needed.

Add OPENAI_API_KEY to validation.credentialEnvVars for both gateways,
matching the pattern used by Hicap and Gitlawb Opengateway.

* chore: trigger mergeability recheck

* feat(shim): forward effort/thinking to OpenCode Zen/Go endpoints

- buildResponsesBody: add reasoning_effort + reasoning_summary + include
- buildAnthropicMessagesBody: add thinking config (adaptive/enabled/budget)
- buildGeminiBody: add thinkingConfig with thinkingLevel mapping
- modelSupportsEffort: allow OpenCode Claude and Gemini models
- modelSupportsMaxEffort: add opus-4-7
- getAvailableEffortLevels: show standard levels for OpenCode native models
- opencode-go: add missing validation block

* feat: update OpenCode Zen and Go model counts, add new models, and enhance effort level handling

* feat: implement xhigh effort support for specific models and adjust effort level handling

* fix(effort): address reviewer feedback on xhigh + new models

- docs/advanced-setup.md: bump OpenCode Go count 12 → 13
- openaiShim.ts: include opus-4-8 / opus-4.8 in the adaptive thinking
  detection so the new model uses the adaptive + effort path instead
  of falling back to budgetTokens
- effort.ts: modelUsesOpenAIEffort now also rejects models that include
  'claude-' or 'gemini-' — without this, OpenCode Claude/Gemini
  routes (provider=openai) were misclassified as OpenAI-style and
  could leak xhigh past the new gate
- effort.codex.test.ts: lock in the new exclusion with a regression
  test against the openai provider

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(effort): address reviewer feedback on xhigh effort + new models

Closes the three P2 findings from PR Twigpine#1505 review:

1. Settings schema now accepts 'xhigh' so a persisted xhigh survives
   restart instead of being silently dropped by .catch(undefined).
2. ModelPicker /effort cycle is driven by getAvailableEffortLevels(model)
   instead of a boolean includeMax, so models supporting xhigh
   (opus-4-7/4-8, OpenAI/Codex) can actually select it from the picker.
   displayEffort clamp now uses the available levels list, so stale
   xhigh also clamps to high when the focused model doesn't support it.
3. SDK/control metadata uses getAvailableEffortLevels(model) instead of
   the EFFORT_LEVELS fallback that advertised xhigh to every max-capable
   model. SDK schema + generated types extended to include 'xhigh'.

Also fixes a latent generator bug: the array case in generate-sdk-types
now parenthesizes union/intersection elements so the trailing [] binds
the whole type, e.g. ("a"|"b")[] rather than "a"|"b[]. Without this,
the regenerated xhigh levels ended up typed as the single-literal
"xhigh"[] and broke the modelInfo assignability check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore(effort): order xhigh before max in EFFORT_LEVELS

EFFORT_LEVELS now matches getAvailableEffortLevels() output order
(['low', 'medium', 'high', 'xhigh', 'max']), and the order asserted by
the existing effort.codex.test.ts tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore(effort): order xhigh before max in settings + SDK schemas

Matches the EFFORT_LEVELS / getAvailableEffortLevels order from the
previous commit. The Zod enum order doesn't affect runtime validation,
but keeps the source consistent and avoids confusion if anyone reads
the enum literal to infer display order.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(effort): clamp ModelPicker selection and mark xhigh as current

- ModelPicker.handleSelect: clamp the emitted/persisted effort to the
  focused model's available levels so a toggled-but-unsupported level
  (e.g. 'xhigh' on a model that doesn't support it) is never written
  to settings.json or handed to the consumer. Add focusedAvailableLevels
  + focusedDefaultEffort to the memo guard so the function regenerates
  when the focused model changes.
- EffortPicker: compare the xhigh option against the persisted 'xhigh'
  level directly. The 'max' alias path is kept only for legacy
  settings.json values that still hold 'max' from before xhigh was
  introduced.

* docs(effort): fix stale EffortPicker comment about xhigh normalization

openAIEffortToStandard is a type cast that passes 'xhigh' through as a
first-class EffortLevel — the shim only converts to 'max' at the
Anthropic request boundary, not here. Update the comment to match.

* docs(effort): update /effort help to match xhigh support matrix

The /effort --help output still described max as "Opus 4.6 only" and
xhigh as an "alias for max", but this PR promotes xhigh to a first-class
EffortLevel and allows it for OpenCode Claude Opus 4.7/4.8 (with max
also allowed for those Opus variants). Update the help so it matches
the picker/runtime behavior:
- max: "(Opus 4.6+)"
- xhigh: "(OpenAI/Codex and Opus 4.7+)"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(sdk): address reviewer P2 — sync xhigh across override union, schemas, CLI

- Add 'xhigh_effort' to ModelCapabilityOverride union so the new
  call at effort.ts:93 typechecks (P2 finding 1).
- Add 'xhigh' to AgentDefinition.effort enum (coreSchemas.ts) and
  control.applied.effort enum (controlSchemas.ts), then regenerate
  coreTypes.generated.ts so the SDK public contract matches the
  first-class effort level (P2 finding 2).
- Add 'xhigh' to the --effort CLI flag allowed list and help text
  (main.tsx:945-951) so users can actually pass --effort xhigh
  instead of hitting "It must be one of: low, medium, high, max".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(effort): narrow allowlist to shim-serialized models; sync max description

Address reviewer findings on PR Twigpine#1505:

P2: The broad `m.includes('opus-4') || m.includes('sonnet-4')` branch
made older variants (claude-opus-4-1, claude-sonnet-4-5) advertise
effort support, but the Anthropic /messages shim only serializes
low/medium as anthropicBody.effort for the isAdaptive || isOpus45
set (opus-4-5/4-6/4-7/4-8, sonnet-4-6). For other models the shim
only emits thinking for high/max, so low/medium on those models
was silently dropped on the wire. Collapse the two 4-model branches
into one that matches the shim's serialization set; the substring
match still covers prefix variations (claude-, opencode-claude-).

P3: getEffortLevelDescription('max') said "Opus 4.6 only" but
modelSupportsMaxEffort now allows opus-4-6, opus-4-7, opus-4-8.
Update the shared description to "Opus 4.6+" so the picker and
/effort confirmation agree with the new support matrix (matching
the /effort --help text from 3cf5de2).

Add effort.codex.test.ts coverage: assert that opus-4-5/4-6/4-7/4-8
and sonnet-4-6 support effort, while opus-4-1, opus-4-2, and
sonnet-4-5 do not (the latter three were previously true via the
broad substring match and are now correctly excluded).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: trigger CodeRabbit re-review

* fix(effort): gate modelSupportsXHighEffort on modelSupportsEffort

---------

Co-authored-by: Gravirei <gravirei@users.noreply.github.com>
Co-authored-by: OpenClaude (mimo-v2.5-pro) <openclaude@gitlawb.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants